package nba2kmodtool.filedesc;

import java.io.File;
import java.io.IOException;

import nba2kmodtool.util.ByteFileReader;
import nba2kmodtool.util.FileOperation;
import nba2kmodtool.util.H7CompressUtils;
import nba2kmodtool.util.ProgressDialog;
import nba2kmodtool.util.ZlibUtils;

class N2kCdfFileDecompress {
	private static final boolean IS_DEBUG = BaseIffFile.IS_DEBUG;

	private BaseIffFile iff;
	private float percent;
	private ProgressDialog progressDialog;

	N2kCdfFileDecompress(BaseIffFile iff) {
		this.iff = iff;
	}

	void writeDecompressFile(ByteFileReader in, ByteFileReader out) throws IOException {
		try {
			//copy IFF index file
			FileOperation.copyFileData(in, out);
			File cdfFile = iff.cdfFile;
			ByteFileReader cdfin = new ByteFileReader(cdfFile, "r");
			File cdfOutFile = new File(cdfFile.getPath() + ".temp");
			ByteFileReader cdfout = new ByteFileReader(cdfOutFile, "rw");
			int index = 0;
			int fileNum = iff.fileNum;
			this.percent = 0;
			int total = iff.blocks.length;
			this.progressDialog = new ProgressDialog(null);
			for (int i = 0; i < fileNum; i++) {
				for (int s = 0; s < iff.dataFiles[i].partNum; s++) {
					IffBlock block = iff.blocks[index];
					block.blockAddr = cdfout.getFilePointer();
					iff.dataFiles[i].partAddr[s] = block.blockAddr;
					String compressType = cdfin.readBytesAsString(4);
					long decompressSize = cdfin.readBytesAsLong(4, true);
					long compressSize = cdfin.readBytesAsLong(4, true);
					long numb4 = cdfin.readBytesAsLong(4, true);
					if (block.blockSize != decompressSize || block.compressedSize != compressSize) {
						cdfin.close();
						cdfout.close();
						throw new IOException("UnSupport IFF File: " + iff.file.getPath() + ",\n" + cdfFile.getPath());
					}
					if (N2kIffFileDecompress.ZLIB_COMPRESS.equals(compressType)) {
						long datalen = compressSize - 16;
						byte[] src = new byte[(int) datalen];
						cdfin.read(src);
						byte[] outbuf = ZlibUtils.decompress(src);
						cdfout.write(outbuf);
						block.blockSize = outbuf.length;
					} else if (N2kIffFileDecompress.isH7Compress(compressType)) {
						int hL = cdfin.readBytesAsInt(4, true);
						long datalen = compressSize - 20;
						byte[] src = new byte[(int) datalen];
						cdfin.read(src);
						byte[] outbuf = H7CompressUtils.decompress(src, (int) decompressSize, hL);
						cdfout.write(outbuf);
					} else {
						cdfin.seek(block.blockAddr);
						byte[] src = new byte[(int) block.compressedSize];
						cdfin.read(src);
						cdfout.write(src);
					}
					index++;
					this.percent = ((float) index / total * 100);
					progressDialog.changeValue(percent);
				}
			}
			cdfout.setLength(cdfout.getFilePointer());
			cdfin.close();
			cdfout.close();
			File bakFile = new File(cdfFile.getPath() + ".bak");
			if (bakFile.exists()) {
				bakFile.delete();
			}
			if (!cdfFile.renameTo(bakFile)) {
				throw new IOException("Can`t Rename Temp File");
			}
			cdfOutFile.renameTo(cdfFile);
			//Fix Header Data
			in.seek(0x20);
			long next1 = in.getFilePointer() + in.read4BytesAsInt() - 1;
			long next2 = in.getFilePointer() + in.read4BytesAsInt() - 1;
			for (int i = 0; i < fileNum; i++) {
				out.seek(next1 + 4 * iff.fileNum + i * 8 * iff.dataFiles[i].partNum);
				for (int j = 0; j < iff.dataFiles[i].partNum; j++) {
					out.writeIntBigEndin((int) iff.dataFiles[i].partAddr[j]);
					out.writeIntBigEndin((int) iff.dataFiles[i].partSize[j]);
				}
			}
		} finally {
			if (this.progressDialog != null) {
				this.progressDialog.dispose();
			}
			this.progressDialog = null;
		}
	}
}
